package ccnt.pvc.scudwaremobile.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import ccnt.pvc.scudwaremobile.bean.ScudRequest;
import ccnt.pvc.scudwaremobile.dao.ServiceModel;
import ccnt.pvc.scudwaremobile.server.ScudwareServer;
import ccnt.pvc.scudwaremobile.service.ServiceManager.ServiceManagerBinder;
import ccnt.pvc.scudwaremobile.utils.Constants.MessageCode;
import ccnt.pvc.scudwaremobile.utils.IDataService;
import ccnt.pvc.scudwaremobile.utils.JsonUtils;

import com.google.gson.Gson;

import edu.mit.media.funf.Utils;
import edu.mit.media.funf.configured.ConfiguredPipeline;
import edu.mit.media.funf.storage.BundleSerializer;

public class MainService extends ConfiguredPipeline {

	private final static String TAG = MainService.class.getName();

	private Map<String, Messenger> registerMap = new HashMap<String, Messenger>();
	private Map<String, ArrayList<String>> appToServicesMap = 
			new HashMap<String, ArrayList<String>>();
	private Map<String, ScudwareServiceConnection> connMap = 
			new HashMap<String, ScudwareServiceConnection>();
	
	private MiddlewareServiceConnection<ServiceManagerBinder> serviceManagerCoon = 
			new MiddlewareServiceConnection<ServiceManagerBinder>();
	private ScudwareServer server;
	
	@Override
	public void onCreate() {
		super.onCreate();
		
		// TODO 绑定service
		initService();
		
		// TODO 运行server
		Log.d(TAG, "start server");
		server = new ScudwareServer(this);
		server.setDaemon(true);
		server.start();
	}

	private void initService() {
		//绑定ServiceManager服务
		bindService(new Intent(MainService.this, ServiceManager.class),
				serviceManagerCoon, BIND_AUTO_CREATE);
	}
	
	@Override
	public void onDestroy() {
		// TODO 关闭service
		stopService();
		// TODO 关闭server
		server.close();
		server.interrupt();
		
		super.onDestroy();
	}
	
	private void stopService() {
		unbindService(serviceManagerCoon);
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind:" + TAG);
		return mMessenger.getBinder();
	}
	
	@Override
	public void handleScudewareMsg(Message msg) {
		Log.d(TAG, "msg receivd");
		
		Bundle data = msg.getData();
		if(data == null)
			return;
		
		String strRequest = data.getString("ScudRequest");
		Log.d(TAG, strRequest);
		ScudRequest request = new Gson().fromJson(strRequest, ScudRequest.class);
		String action = request.getAction();
		if(action.equals(ScudRequest.ACTION_QUERY)) {
			handleQuery(msg, request);
		} else if(action.equals(ScudRequest.ACTION_REGISTER)) {
			handleRegister(msg, request);
		} else if(action.equals(ScudRequest.ACTION_UNREGISTER)) {
			handleUnregister(msg, request);
		} else if(action.equals(ScudRequest.ACTION_REQUEST)) {
			handleRequest(msg, request);
		}
		
	}	
	
	private void handleRequest(Message msg, ScudRequest request) {
		String registerName = request.getRegisterName();
		Log.d(TAG, "app request: " + registerName);
		
		if(!registerMap.containsKey(registerName)) {
			Log.d(TAG, "app not register: " + registerName);
			return;
		}
		
		Messenger replyMessenger = registerMap.get(registerName);
		Message replyMsg = Message.obtain(null, MessageCode.RESPONSE_REQUEST, 0, 0);
		Bundle data = new Bundle();
		
		String value = null;
		for(String className : appToServicesMap.get(registerName)) {
			try {
				ScudwareServiceConnection conn = connMap.get(className);
				if(conn == null)
					return;
				
				IDataService service = conn.getiDataService();
				if(service == null)
					return;
				
				Bundle bundle = service.getData();
				value = getBundleSerializer().serialize(bundle);
			} catch (RemoteException e1) {
				e1.printStackTrace();
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
		data.putString("data", value);
		replyMsg.setData(data);
		try {
			replyMessenger.send(replyMsg);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	private void handleUnregister(Message msg, ScudRequest request) {
		String registerName = request.getRegisterName();
		Log.d(TAG, "app unregister: " + registerName);
		synchronized (registerMap) {
			if(registerMap.containsKey(registerName)) {
				registerMap.remove(registerName);
			}
		}
		
		// TODO 关闭对应的Service
		ArrayList<String> list = appToServicesMap.get(registerName);
		for(String className : list) {
			stopScudwareService(className);
		}
		appToServicesMap.remove(registerName);
	}

	private void handleRegister(Message msg, ScudRequest request) {
		Messenger messenger = msg.replyTo;
		String registerName = request.getRegisterName();
		Log.d(TAG, "app register: " + registerName);
		//保存app的messenger对象
		if(registerName!=null && messenger!=null) {
			synchronized (registerMap) {
				registerMap.put(registerName, messenger);
			}
		}
		
		// TODO 查找到需要的service
		String className = request.getServices().get(0).getClassName();
		ServiceModel service = getServiceManager().getServiceByClassName(className);
		ArrayList<String> list = new ArrayList<String>();
		list.add(className);
		appToServicesMap.put(registerName, list);
		
		// TODO 启动Service
		startScudwareService(service);
	}

	private void handleQuery(Message msg, ScudRequest request) {
		Messenger replyMessenger = msg.replyTo;
		String registerName = request.getRegisterName();
		Log.d(TAG, "service query: " + registerName);
		
		List<ServiceModel> filters = request.getServices();
		List<ServiceModel> services = getServiceManager().getServices(filters);
		
		Message replyMsg = Message.obtain(null, MessageCode.RESPONSE_QUERY, 0, 0);
		Bundle data = new Bundle();
		data.putString("services", new Gson().toJson(services));
		replyMsg.setData(data);
		try {
			replyMessenger.send(replyMsg);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	@Override
	public BundleSerializer getBundleSerializer() {
		return new BundleToJson();
	}
	
	public static class BundleToJson implements BundleSerializer {
		public String serialize(Bundle bundle) {
			return JsonUtils.getGson().toJson(Utils.getValues(bundle));
		}
	}
	
	//Service Connection
	public ServiceManager getServiceManager() {
		return serviceManagerCoon.getBinder().getService();
	}
	
	private boolean startScudwareService(ServiceModel service) {
		String className = service.getClassName();
		if(connMap.containsKey(className)) {
			Log.d(TAG, "service already running: " + className);
			connMap.get(className).addCount();
			return false;
		}
		
		Log.d(TAG, "going to run service: " + className);
		Intent intent = new Intent();
		intent.setClassName(service.getPackageName(), service.getClassName());
		ScudwareServiceConnection conn = new ScudwareServiceConnection();
		bindService(intent, conn, BIND_AUTO_CREATE);
		synchronized (connMap) {
			connMap.put(service.getClassName(), conn);
		}
		return true;
	}
	
	private boolean stopScudwareService(String className) {
		synchronized (connMap) {
			if(connMap.containsKey(className)) {
				ScudwareServiceConnection conn = connMap.get(className);
				if(conn.isCountZero()) {
					unbindService(conn);
				} else {
					conn.minusCount();
				}
				connMap.remove(className);
			}
		}
		return true;
	}
}
